/*
*	Project: Aethon
*
*	File: Terrain.h
*
*	Author: Caleb Reinking
*
*	Date: 2/15/2009
*
*   Purpose: The Terrain class builds the terrain using a heightmap file and 
*            bitmap texture. The heightmap file format is found at the bottom of
*            this specification file. It consists of a dimension, separation
*            factor, and the heights at every (x,z) point on the surface. The 
*            heights can never be negative. 
*            Terrain Class Specification File
*/

#ifndef TERRAIN_HEADER
#define TERRAIN_HEADER

#define MAX_MAP_SIZE 512

#include "../include/CollisionSphere.h"
#include "../include/ModelPart.h"
#include <math.h>
#include <string>

using namespace std;

//#############################################################################
class Terrain{

    private:
       bool hasVisibility;
       bool hasCollisions;  
       float heightGrid[MAX_MAP_SIZE][MAX_MAP_SIZE];
       ModelPart modPart;
       int dimension;
       float separationFact;
       GLuint terrainId;
	
	public:	
	    //------------------- constructors ----------------------------------------
		//##########################################################################
		Terrain()
		{
           hasVisibility = true;
		   hasCollisions = true;
		   modPart = ModelPart();
		   dimension = 0;
		   separationFact = 1.0;
		}

		Terrain( bool vis, bool collision )
		{
		   hasVisibility = vis;
		   hasCollisions = collision;
		   modPart = ModelPart();
		   dimension = 0;
		   separationFact = 1.0;
		  // maxHeightFound = 10.0;
		}
		
		//-------------------------------------------------------------------------	
		//------------------- gets and sets ---------------------------------------
		//##########################################################################
		void setHasVisibility(bool vis) 
		{
			 hasVisibility = vis;
		}//end setHasVisibility
			
		//##########################################################################
		bool getHasVisibility() 
		{
			 return hasVisibility;
		}//end getHasVisibility
			
			
		//##########################################################################
		void setHasCollsions(bool collision) 
		{
			 hasCollisions = collision;
		}//end setHasCollisions
			
		//##########################################################################
		bool getHasCollisions() 
		{
			 return hasCollisions;
		}//end getHasCollisions
		
		float getElementAt( int x, int y )
		{
             return heightGrid[x][y];
        }//end getElementAt
        
        float getHeightAtPoint( float xPt, float zPt )
        {
           // Take the absolute value of the z point so that the math works.
           // The algorithm for interpolating between points and finding the
           // actual height of a specific floating x,z point has not been tested without
           // finding the absolute value
		   zPt =fabs(zPt/separationFact);
           
            
		   xPt = xPt/separationFact;
			
		   // finding all four corners of the square that the model is currently
		   // in so that the interpolation can take place.
           float heightCeilXZ = heightGrid[(int)(xPt+1.0)][(int)(zPt+1.0)];
           float heightFloorXZ = heightGrid[(int)(xPt)][(int)(zPt)];
           float heightCeilXFloorZ = heightGrid[(int)(xPt+1.0)][(int)(zPt)];
           float heightFloorXCeilZ = heightGrid[(int)(xPt)][(int)(zPt+1.0)];
           
           // finding the exact position on the square relative to the bottom
           // left corner of the square
           float fractionalX = xPt - (int)xPt;
           float fractionalZ = zPt - (int)zPt;
           
           // average the change in height along the x axis
           float avgDeltaYinX = ((heightCeilXZ - heightFloorXCeilZ) +
                                 (heightCeilXFloorZ - heightFloorXZ)) / 2.0;
                                 
           // average the change in height along the z axis
           float avgDeltaYinZ = ((heightCeilXZ - heightCeilXFloorZ) +
                                 ( heightFloorXCeilZ - heightFloorXZ)) / 2.0;
                                 
           // based on the change in height across the entire square, the height
           // at the current position can be obtained by taking the base height
           // at the bottom left corner and adding the change in height multiplied
           // by the fractional part along the x and z axes.
           return (float)(heightGrid[(int)(xPt)][(int)(zPt)]+
                  (((fractionalX*avgDeltaYinX) + (fractionalZ*avgDeltaYinZ)) /2.0));
           
           
        }//end getHeightAtPoint
				
	   void display();
	   int collidesWith( CollisionSphere sphere );
	   int load( string heightFileName, string texFileName );
	
};//end class

#endif //TERRAIN_HEADER

/*Terrain heightmap specification file format

<beginning of file>
4 0.5               // int dimension followed by float seperation Factor
10 13 18 20         // a 4x4 (dimension x dimension) grid of int heights
17 16 12 8
12 15 16 12
5 12 13 15
<end of file>

